package org.zstack.network.service.virtualrouter.vyos;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.appliancevm.ApplianceVmAsyncHttpCallMsg;
import org.zstack.appliancevm.ApplianceVmRefreshFirewallMsg;
import org.zstack.appliancevm.ApplianceVmRefreshFirewallReply;
import org.zstack.core.CoreGlobalProperty;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.Q;
import org.zstack.header.core.Completion;
import org.zstack.header.core.workflow.Flow;
import org.zstack.header.core.workflow.FlowChain;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.host.HypervisorType;
import org.zstack.header.message.MessageReply;
import org.zstack.header.vm.VmInstanceConstant;
import org.zstack.header.vm.VmNicVO;
import org.zstack.network.service.vip.VipVO;
import org.zstack.network.service.vip.VipVO_;
import org.zstack.network.service.virtualrouter.*;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import org.zstack.utils.network.NetworkUtils;

import java.util.ArrayList;
import java.util.List;

import static org.zstack.core.Platform.operr;

/**
 * Created by xing5 on 2016/10/31.
 */
public class VyosVm extends VirtualRouter {
    private static final CLogger logger = Utils.getLogger(VyosVm.class);

    @Autowired
    private VyosVmFactory vyosf;

    public VyosVm(VirtualRouterVmVO vo) {
        super(vo);
    }

    protected List<Flow> createBootstrapFlows(HypervisorType hvType) {
        List<Flow> flows = new ArrayList<>();

        flows.add(apvmf.createBootstrapFlow(hvType));
        if (!CoreGlobalProperty.UNIT_TEST_ON) {
            flows.add(new VyosGetVersionFlow());
            flows.add(new VyosWaitAgentStartFlow());
            flows.add(new VyosDeployAgentFlow());
        }

        return flows;
    }

    @Override
    protected List<Flow> getPostCreateFlows() {
        return vyosf.getPostCreateFlows();
    }

    @Override
    protected List<Flow> getPostStartFlows() {
        return vyosf.getPostStartFlows();
    }

    @Override
    protected List<Flow> getPostStopFlows() {
        return vyosf.getPostStopFlows();
    }

    @Override
    protected List<Flow> getPostRebootFlows() {
        return vyosf.getPostRebootFlows();
    }

    @Override
    protected List<Flow> getPostDestroyFlows() {
        return vyosf.getPostDestroyFlows();
    }

    @Override
    protected List<Flow> getPostMigrateFlows() {
        return vyosf.getPostMigrateFlows();
    }

    @Override
    protected FlowChain getReconnectChain() {
        return vyosf.getReconnectFlowChain();
    }

    @Override
    protected FlowChain getProvisionConfigChain() {
        return vyosf.getFlushConfigChain();
    }

    @Override
    protected void handle(final ApplianceVmRefreshFirewallMsg msg) {
        // vyos doesn't need appliance vm
        ApplianceVmRefreshFirewallReply reply = new ApplianceVmRefreshFirewallReply();
        bus.reply(msg, reply);
    }

    @Override
    protected void handle(final ApplianceVmAsyncHttpCallMsg msg) {
        // vyos doesn't need appliance vm
        throw new CloudRuntimeException("should not be called");
    }

    public void configureKeepalived(VyosKeepalivedCommands.VyosHaEnableCmd cmd,
                                       Completion completion) {
        if (!vr.isHaEnabled()) {
            completion.success();
        }

        VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg();
        msg.setPath(VyosKeepalivedCommands.VYOS_HA_ENABLE_PATH);
        msg.setCommand(cmd);
        msg.setVmInstanceUuid(vr.getUuid());
        bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid());
        bus.send(msg, new CloudBusCallBack(completion) {
            @Override
            public void run(MessageReply reply) {
                if (!reply.isSuccess()) {
                    completion.fail(reply.getError());
                    return;
                }

                VirtualRouterAsyncHttpCallReply re = reply.castReply();
                VyosKeepalivedCommands.VyosHaEnableRsp ret = re.toResponse(VyosKeepalivedCommands.VyosHaEnableRsp.class);
                if (!ret.isSuccess()) {
                    ErrorCode err = operr("failed to enable ha on virtual router[uuid:%s], %s",
                            vr.getUuid(), ret.getError());
                    completion.fail(err);
                } else {
                    logger.debug(String.format("enable ha on virtual router[uuid:%s] successfully", vr));
                    completion.success();
                }
            }
        });
    }
}
